﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
#endregion

namespace Infusion.Silverlight.Controls.Menu
{
    #region Delegates...
    public delegate void MenuItemClickEventHandler(object sender, MouseButtonEventArgs e);
    #endregion

    #region : MenuItem :
    #region TemplateParts...
    [TemplatePart(Name = MenuItem.MenuItemLayoutRoot, Type = typeof(Grid))]
    [TemplatePart(Name = MenuItem.RectHighlight, Type = typeof(Rectangle))]
    [TemplatePart(Name = MenuItem.RectHighlightSubMenu, Type = typeof(Rectangle))]
    [TemplatePart(Name = MenuItem.RectIconHighlight, Type = typeof(Rectangle))]
    [TemplatePart(Name = MenuItem.ImgImage, Type = typeof(Image))]
    [TemplatePart(Name = MenuItem.GridText, Type = typeof(Grid))]
    [TemplatePart(Name = MenuItem.TxtText, Type = typeof(TextBlock))]
    [TemplatePart(Name = MenuItem.CanvasSubMenuBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = MenuItem.LineSubMenuBorder, Type = typeof(Line))]
    [TemplatePart(Name = MenuItem.ImgArrow, Type = typeof(Image))]
    [TemplatePart(Name = MenuItem.CanvasClickSurface, Type = typeof(Canvas))]
    #endregion
    public class MenuItem : Control, IMenuItem
    {
        #region Events...
        public event MenuItemClickEventHandler MenuItemClick;
        #endregion

        #region TemplatePart Names...
        public const string MenuItemLayoutRoot = "MenuItemLayoutRoot";
        public const string RectHighlight = "RectHighlight";
        public const string RectHighlightSubMenu = "RectHighlightSubMenu";
        public const string RectIconHighlight = "RectIconHighlight";
        public const string ImgImage = "ImgImage";
        public const string GridText = "GridText";
        public const string TxtText = "TxtText";
        public const string CanvasSubMenuBorder = "CanvasSubMenuBorder";
        public const string LineSubMenuBorder = "LineSubMenuBorder";
        public const string ImgArrow = "ImgArrow";
        public const string CanvasClickSurface = "CanvasClickSurface";
        #endregion

        #region TemplatePart Variables...
        internal Grid menuItemLayoutRoot;
        internal Rectangle rectHighlight;
        internal Rectangle rectHighlightSubMenu;
        internal Rectangle rectIconHighlight;
        internal Image imgImage;
        internal Grid gridText;
        internal TextBlock txtText;
        internal Canvas canvasSubMenuBorder;
        internal Line lineSubMenuBorder;
        internal Image imgArrow;
        internal Canvas canvasClickSurface;
        #endregion

        #region Class Variables...
        private Menu parentMenu = null;
        private bool templateApplied = false;
        private string accessKey = string.Empty;
        private double yOffset = 0d;
        private DispatcherTimer menuShowTimer;
        private bool mouseOver = false;
        private bool inFocus = false;
        #endregion

        #region Constants...
        private const string SubMenuImageUri = "Images/RightArrow.png";
        #endregion

        #region Dependency Properties...
        #region EnabledProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.MenuItem.Enabled dependency property.
        /// </summary>
        public static readonly DependencyProperty EnabledProperty = DependencyProperty.Register(
            "Enabled",
            typeof(bool),
            typeof(MenuItem),
            new PropertyMetadata(new PropertyChangedCallback(EnabledPropertyChanged)));
        #endregion

        #region TextProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.MenuItem.Text dependency property.
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            "Text",
            typeof(string),
            typeof(MenuItem),
            null);
        #endregion

        #region MenuIDProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.MenuItem.MenuID dependency property.
        /// </summary>
        public static readonly DependencyProperty MenuIDProperty = DependencyProperty.Register(
            "MenuID",
            typeof(string),
            typeof(MenuItem),
            new PropertyMetadata(new PropertyChangedCallback(MenuIDPropertyChanged)));
        #endregion

        #region ImageSourceProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Menu.Menu.ImageSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
            "ImageSource",
            typeof(string),
            typeof(MenuItem),
            null);
        #endregion
        #endregion

        #region Dependency Property Changed Handlers...
        #region EnabledPropertyChanged
        public static void EnabledPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            MenuItem menuItem = (MenuItem)obj;

            if (args.NewValue != null)
            {
                bool enabled = (bool)args.NewValue;
                if (menuItem.txtText != null)
                {
                    menuItem.SetEnabledVisualStyle();
                }
            }
        }
        #endregion

        #region MenuIDPropertyChanged
        public static void MenuIDPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            MenuItem menuItem = (MenuItem)obj;

            if (args.NewValue != null)
            {
                string menuID = args.NewValue.ToString();

                if (menuItem.templateApplied)
                {
                    menuItem.gridText.ColumnDefinitions[1].Width = new GridLength(23);
                    menuItem.imgArrow.Source = new BitmapImage(new Uri(SubMenuImageUri, UriKind.Relative));
                    if (menuItem.MenuItemClick != null)
                    {
                        menuItem.canvasSubMenuBorder.Visibility = Visibility.Visible;
                    }
                }
            }
        }
        #endregion
        #endregion

        #region Constructor(s)...
        #region MenuItem
        public MenuItem() : base()
        {
            Enabled = true;

            DefaultStyleKey = typeof(MenuItem);
            SetValue(Control.IsTabStopProperty, true);

            menuShowTimer = new DispatcherTimer();
            menuShowTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
            menuShowTimer.Tick += new EventHandler(menuShowTimer_Tick);

            GotFocus += new RoutedEventHandler(MenuItem_GotFocus);
            LostFocus += new RoutedEventHandler(MenuItem_LostFocus);
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region menuShowTimer_Tick
        private void menuShowTimer_Tick(object sender, EventArgs e)
        {
            menuShowTimer.Stop();

            //OpenSubMenu(true, false);
        }
        #endregion

        #region MenuItem_GotFocus
        private void MenuItem_GotFocus(object sender, RoutedEventArgs e)
        {
            inFocus = true;

            if (ParentMenu != null)
            {
                //ParentMenu.HideSubMenus((MenuItem)sender);
            }

            if (Enabled)
            {
                rectHighlight.Fill = Helper.GetBrush(LinearGradientBrushes.MenuItemHighlightEnabled);
                rectHighlight.Stroke = Helper.GetBrush(SolidColorBrushes.MenuItemHighlightEnabledStroke);

                if (mouseOver)
                {
                    //if (!subMenuOpen)
                    //{
                    //    if (!string.IsNullOrEmpty(MenuID))
                    //        menuShowTimer.Start();
                    //}
                }

                if (!string.IsNullOrEmpty(MenuID) && MenuItemClick != null)
                {
                    lineSubMenuBorder.Y1 -= 4;
                    lineSubMenuBorder.Y2 += 4;
                    lineSubMenuBorder.Stroke = Helper.GetBrush(SolidColorBrushes.MenuItemSubMenuBorder);

                    rectHighlightSubMenu.Visibility = Visibility.Visible;
                }

                rectHighlight.Visibility = Visibility.Visible;
            }
            else
            {
                if (!mouseOver)
                {
                    rectHighlight.Fill = Helper.GetBrush(LinearGradientBrushes.MenuItemHighlightDisabled);
                    rectHighlight.Stroke = Helper.GetBrush(SolidColorBrushes.MenuItemHighlightDisabledStroke);
                    rectHighlight.Visibility = Visibility.Visible;
                }
            }
        }
        #endregion

        #region MenuItem_LostFocus
        private void MenuItem_LostFocus(object sender, RoutedEventArgs e)
        {
            inFocus = false;

            //if (!subMenuOpen)
            //{
                rectHighlight.Visibility = Visibility.Collapsed;
                menuShowTimer.Stop();
            //}

            if (!string.IsNullOrEmpty(MenuID) && MenuItemClick != null)
            {
                lineSubMenuBorder.Y1 += 4;
                lineSubMenuBorder.Y2 -= 4;
                lineSubMenuBorder.Stroke = Helper.GetBrush(SolidColorBrushes.MenuItemSubMenuBorderHighlight);

                rectHighlightSubMenu.Visibility = Visibility.Collapsed;
            }
        }
        #endregion

        private void canvasClickSurface_MouseEnter(object sender, MouseEventArgs e)
        {
            mouseOver = true;
            Focus();
        }

        private void canvasClickSurface_MouseLeave(object sender, MouseEventArgs e)
        {
            mouseOver = false;
            parentMenu.Focus();
        }

        private void canvasClickSurface_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (Enabled)
            {
                bool forceSubMenuOpen = false;

                if (!string.IsNullOrEmpty(MenuID))
                {
                    if (MenuItemClick != null)
                    {
                        Point clickPoint = e.GetPosition(canvasClickSurface);
                        if (clickPoint.X > canvasClickSurface.ActualWidth - 23)
                        {
                            forceSubMenuOpen = true;
                        }
                    }
                    else
                    {
                        forceSubMenuOpen = true;
                    }
                }

                menuShowTimer.Stop();

                Click(true, forceSubMenuOpen, false, e);
            }
        }
        #endregion

        #region Methods...
        #region Click
        public void Click(bool useSubMenuAnimation, bool forceSubMenuOpen, bool focusFirstSubItem, MouseButtonEventArgs e)
        {
            if (Enabled)
            {
                if (!forceSubMenuOpen)
                {
                    //if (Group != null)
                    //{
                    //    Selection = MenuItemSelectionType.Group;
                    //}

                    if (MenuItemClick != null)
                        MenuItemClick(this, e);

                    ParentMenu.Hide(true);
                }
                else
                {
                    if (!string.IsNullOrEmpty(MenuID))
                    {
                        //OpenSubMenu(useSubMenuAnimation, focusFirstSubItem);
                    }
                }
            }
        }
        #endregion

        #region SetEnabledVisualStyle
        internal void SetEnabledVisualStyle()
        {
            if (Enabled)
            {
                txtText.Foreground = Helper.GetBrush(SolidColorBrushes.MenuItemTextEnabled);
                imgImage.Opacity = 1.0d;
            }
            else
            {
                txtText.Foreground = Helper.GetBrush(SolidColorBrushes.MenuItemTextDisabled);
                imgImage.Opacity = 0.5d;
            }
        }
        #endregion

        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (!templateApplied)
            {
                menuItemLayoutRoot = (Grid)GetTemplateChild(MenuItemLayoutRoot);
                rectHighlight = (Rectangle)GetTemplateChild(RectHighlight);
                rectHighlightSubMenu = (Rectangle)GetTemplateChild(RectHighlightSubMenu);
                rectIconHighlight = (Rectangle)GetTemplateChild(RectIconHighlight);
                imgImage = (Image)GetTemplateChild(ImgImage);
                gridText = (Grid)GetTemplateChild(GridText);
                txtText = (TextBlock)GetTemplateChild(TxtText);
                canvasSubMenuBorder = (Canvas)GetTemplateChild(CanvasSubMenuBorder);
                lineSubMenuBorder = (Line)GetTemplateChild(LineSubMenuBorder);
                imgArrow = (Image)GetTemplateChild(ImgArrow);
                canvasClickSurface = (Canvas)GetTemplateChild(CanvasClickSurface);

                if (!string.IsNullOrEmpty(Text))
                    SetText();

                if (!string.IsNullOrEmpty(ImageSource))
                    imgImage.Source = new BitmapImage(new Uri(ImageSource, UriKind.Relative));

                SetEnabledVisualStyle();

                if (!string.IsNullOrEmpty(MenuID))
                {
                    gridText.ColumnDefinitions[1].Width = new GridLength(23);
                    imgArrow.Source = new BitmapImage(new Uri(SubMenuImageUri, UriKind.Relative));
                    if (MenuItemClick != null)
                    {
                        canvasSubMenuBorder.Visibility = Visibility.Visible;
                    }
                }

                canvasClickSurface.MouseEnter += new MouseEventHandler(canvasClickSurface_MouseEnter);
                canvasClickSurface.MouseLeave += new MouseEventHandler(canvasClickSurface_MouseLeave);
                canvasClickSurface.MouseLeftButtonDown += new MouseButtonEventHandler(canvasClickSurface_MouseLeftButtonDown);

                templateApplied = true;
            }
        }
        #endregion

        #region SetText
        private void SetText()
        {
            txtText.Text = string.Empty;

            int accessKeyIndex = Text.IndexOf('_');

            if (accessKeyIndex > -1)
            {
                if (accessKeyIndex > 0)
                {
                    Run startRun = new Run();
                    startRun.Text = Text.Substring(0, accessKeyIndex);
                    txtText.Inlines.Add(startRun);
                }

                Run accessKeyRun = new Run();
                accessKeyRun.TextDecorations = TextDecorations.Underline;
                accessKeyRun.Text = Text.Substring(accessKeyIndex + 1, 1);
                txtText.Inlines.Add(accessKeyRun);

                accessKey = accessKeyRun.Text;

                if (accessKeyIndex < Text.Length - 1)
                {
                    Run endRun = new Run();
                    endRun.Text = Text.Substring(accessKeyIndex + 2);
                    txtText.Inlines.Add(endRun);
                }
            }
            else
            {
                txtText.Text = Text;
            }
        }
        #endregion
        #endregion

        #region Properties...
        #region ParentMenu
        public Menu ParentMenu
        {
            get { return parentMenu; }
            set { parentMenu = value; }
        }
        #endregion

        #region Text
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        #endregion

        #region MenuID
        public string MenuID
        {
            get { return (string)GetValue(MenuIDProperty); }
            set { SetValue(MenuIDProperty, value); }
        }
        #endregion

        #region Enabled
        public bool Enabled
        {
            get { return (bool)GetValue(EnabledProperty); }
            set { SetValue(EnabledProperty, value); }
        }
        #endregion

        #region ImageSource
        public string ImageSource
        {
            get { return (string)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }
        #endregion

        #region AccessKey
        public string AccessKey
        {
            get { return accessKey; }
        }
        #endregion

        #region YOffset
        public double YOffset
        {
            get { return yOffset; }
            set { yOffset = value; }
        }
        #endregion

        public double RealWidth
        {
            get { return (double)GetValue(FrameworkElement.ActualWidthProperty); }
        }

        public double RealHeight
        {
            get { return (double)GetValue(FrameworkElement.ActualHeightProperty); }
        }
        #endregion
    }
    #endregion
}